package nba2kmodtool.filedesc;

import java.io.IOException;

import nba2kmodtool.util.ByteFileReader;
import nba2kmodtool.util.H7CompressUtils;
import nba2kmodtool.util.ZlibUtils;

class N2kIffFileDecompress {
	/**Normal Compress Type*/
	public static final long H7_COMPRESS = 0xC337480EL;
	/**ZLIB Compress Type*/
	public static final String ZLIB_COMPRESS = "ZLIB";

	private static final boolean IS_DEBUG = BaseIffFile.IS_DEBUG;

	private BaseIffFile iff;

	N2kIffFileDecompress(BaseIffFile iff) {
		this.iff = iff;
	}

	static boolean isH7Compress(String compressType) {
		char[] chars = compressType.toCharArray();
		return chars.length >= 4 && chars[0] == 0x0E && chars[1] == 0x48 && chars[2] == 0x37 && chars[3] == 0xC3;
	}

	void writeDecompressFile(ByteFileReader in, ByteFileReader out) throws IOException {
		int fileBlockNum = iff.fileBlockNum;
		byte[] headbuffer = new byte[iff.headerSize];
		in.read(headbuffer);
		out.write(headbuffer);
		for (int i = 0; i < fileBlockNum; i++) {
			//Decompression Data
			if (iff.blocks[i].isCompressed) {
				String compressType = in.readBytesAsString(4);
				long tempSize1 = in.readBytesAsLong(4, true);
				long tempSize2 = in.readBytesAsLong(4, true);
				long numb4 = in.readBytesAsLong(4, true);
				if (IS_DEBUG) {
					System.out
							.printf("Decompress: Cur:%X, Block:%d, CompressType:%s, CompressSize:%d, decompressSize:%d, UnkownNum:%d\n",
									in.getFilePointer(), i, compressType, tempSize2, tempSize1, numb4);
				}
				if (iff.blocks[i].compressedSize != tempSize2) {
					in.close();
					out.close();
					throw new IOException("UnSupport IFF File: " + iff.file.getPath());
				}
				if (ZLIB_COMPRESS.equals(compressType)) {
					long datalen = tempSize2 - 16;
					byte[] src = new byte[(int) datalen];
					in.read(src);
					byte[] outbuf = ZlibUtils.decompress(src);
					out.write(outbuf);
					iff.blocks[i].blockSize = outbuf.length;
				} else if (isH7Compress(compressType)) {
					int hL = in.readBytesAsInt(4, true);
					long datalen = tempSize2 - 20;
					byte[] src = new byte[(int) datalen];
					in.read(src);
					byte[] outbuf = H7CompressUtils.decompress(src, (int) tempSize1, hL);
					out.write(outbuf);
					iff.blocks[i].blockSize = outbuf.length;
				} else {
					throw new IOException("Unknow compress type:" + compressType);
				}
			} else {
				byte[] src = new byte[(int) iff.blocks[i].blockSize];
				in.read(src);
				out.write(src);
			}
			if (i < fileBlockNum - 1) {
				iff.blocks[i + 1].blockAddr = out.getFilePointer();
			}
		}
		iff.fileSize = out.getFilePointer();
		out.setLength(out.getFilePointer());
		out.seek(0x08);
		out.writeInt((int) iff.fileSize);
		//Fix Header Data
		for (int i = 0; i < fileBlockNum; i++) {
			out.seek(0x20 + 0x20 * i + 0x0C);
			if (iff.blocks[i].isCompressed) {
				out.writeIntBigEndin((int) iff.blocks[i].blockSize);
				out.skipBytes(0x04);
				if (i != 0) {
					out.writeIntBigEndin((int) iff.blocks[i].blockAddr);
				} else {
					out.skipBytes(0x04);
				}
				out.writeIntBigEndin((int) iff.blocks[i].blockSize);
			}
		}
	}
}
